<!--
Original Rutt-Etra-Izer JavaScript code by Felix Turner (www.airtight.cc).
Code reduction and WebVfx integration by Dan Dennedy (www.dennedy.org).
-->

<!DOCTYPE HTML>
<html>
    <head>
        <style>
        html, body {
            width: 100%;
            height: 100%;
            margin: 0px;
            overflow: hidden;
            background-color: #000;
        }
        canvas {
            width: 100%;
            height: 100%
        }
        </style>
    </head>
    <body>
        <script src="three.js"></script>
        <script>

function Filter() {
    this.width = window.innerWidth;
    this.height = window.innerHeight;

    // Init WebGL
    this.scene = new THREE.Scene();
    this.camera = new THREE.Camera(75, this.width/this.height, 1, 3000);
    this.camera.position.z = -1000;
    this.renderer = new THREE.WebGLRenderer({
        antialias: true,
        alpha: false,
        clearAlpha: 1,
        sortObjects: false,
        sortElements: false
    });
    this.renderer.setSize(this.width, this.height);
    document.body.appendChild(this.renderer.domElement);

    // Init line generator
    this.lineHolder = new THREE.Object3D();
    this.scene.addObject(this.lineHolder);
}


/**
 * Create Lines from image
 */
Filter.prototype.createLines = function(pixels, opacity, thickness, density, depth) {
    if (this.lineGroup) {
        this.scene.removeObject(this.lineGroup);
        this.lineHolder.removeChild(this.lineGroup);
    }
    this.lineGroup = new THREE.Object3D();

    var material = new THREE.LineBasicMaterial({
        color: 0xffffff,
        opacity: opacity,
        linewidth: thickness,
        blending: THREE.AdditiveBlending,
        depthTest: false,
        vertexColors: true
    });

    // go through the image pixels
    for (var y = 0; y < this.height; y+= density) {
        var geometry = new THREE.Geometry();
        for (var x = 0; x < this.width; x+= density) {
            var color = new THREE.Color(this.getColor(pixels, x, y));
            var brightness = getBrightness(color);
            var posn = new THREE.Vector3(x - this.width/2, y - this.height/2, -brightness * depth + depth/2);
            geometry.vertices.push(new THREE.Vertex(posn));
            geometry.colors.push(color);
        }
        //add a line
        var line = new THREE.Line(geometry, material);
        this.lineGroup.addChild(line);
    }

    this.lineHolder.addChild(this.lineGroup);
}

// Returns a color for a given pixel in the pixel array.
Filter.prototype.getColor = function(pixels, x, y) {
    var base = (Math.floor(y) * this.width + Math.floor(x)) * 4;
    var c = {
        r: pixels[base + 0],
        g: pixels[base + 1],
        b: pixels[base + 2],
        a: pixels[base + 3]
    };
    return (c.r << 16) + (c.g << 8) + c.b;
};

// return pixel brightness between 0 and 1 based on human perceptual bias
function getBrightness(c) {
    return (0.34 * c.r + 0.5 * c.g + 0.16 * c.b);
};

Filter.prototype.render = function() {
    var pixels = webvfx.getImage("video").toImageData().data;
    var opacity = webvfx.getNumberParameter("opacity");
    var thickness = webvfx.getNumberParameter("thickness");
    var density = webvfx.getNumberParameter("density");
    var depth = webvfx.getNumberParameter("depth");
    var scale = webvfx.getNumberParameter("scale");

    // Use defaults where not specified.
    opacity = opacity ? opacity : 1.0;
    thickness = thickness ? thickness : 3.0;
    density = density ? density : 5;
    depth = depth ? depth : 100;
    scale = scale ? scale : 3.0;

    this.createLines(pixels, opacity, thickness, density, depth);
    this.lineHolder.scale = new THREE.Vector3(scale, scale, scale);
    this.lineHolder.rotation.x = webvfx.getNumberParameter("rotation_x") * 2 * Math.PI + Math.PI;
    this.lineHolder.rotation.y = webvfx.getNumberParameter("rotation_y") * 2 * Math.PI + Math.PI;
    this.renderer.render(this.scene, this.camera);
}

function init() {
    var filter = new Filter();
    if (window.webvfx) {
        webvfx.renderRequested.connect(filter, Filter.prototype.render);
        webvfx.imageTypeMap = { "video" : webvfx.SourceImageType };
        webvfx.readyRender(true);
    } else {
        render();
    }
}

window.addEventListener("load", init, false);
        </script>
    </body>
</html>
